using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace WOWEquipOptimizer
{
    /// <summary>
    /// OptimizeAdditional for gems and enchants
    /// </summary>
    class OptimizeAdditional : Optimizer
    {
        // straight forward, optimize each item individually, try each gem
        private Item[] optimizeGems(Item[] items, float oldfitness, List<Item> gems)
        {
            gems.Remove(Gem.None);
            int gemcount = gems.Count;
            if (gemcount == 0) return items;
            if (oldfitness == 0)
            {
                oldfitness = -1;
                bool valid = m_Target.evaluateEquip(items);
                if (valid) oldfitness = m_Target.evaluateTF();
            }
            float maxfitness = oldfitness;
            foreach (Item item in items)
            {
                if (item.SocketCount == 0) continue;
                Gem[] bestgems = (Gem[])item.Gems.Clone();
                int gemmaxcount = (int)Math.Pow(gemcount, item.SocketCount);
                int counter = 0;
                while (counter < gemmaxcount)
                {
                    int slot = counter % item.SocketCount;
                    if (item.GemColors[slot] != GemType.Meta)
                    {
                        item.Gems[slot] = (Gem)gems[(counter / ((int)Math.Pow(gemcount, slot))) % gemcount];
                        bool valid = m_Target.evaluateEquip(items);
                        float fitness = -1;
                        if (valid) fitness = m_Target.evaluateTF();
                        if (fitness > maxfitness)
                        {
                            maxfitness = fitness;
                            bestgems = (Gem[])item.Gems.Clone();
                        }
                        else
                        {
                            item.Gems = (Gem[])bestgems.Clone();
                        }
                    }
                    counter++;
                }
                if (Optimizer.m_Abort) break;
            }
            m_MaxTV = maxfitness;
            return items;
        }
        private Item[] optimizeEnchants(Item[] items, float oldfitness)
        {
            float maxfitness = oldfitness;
            for (int i = 0; i < items.Length; i++)
            {
                if (items[i].Id == Item.NoneId) continue;
                Enchant oldenchant = items[i].Enchant;
                Enchant bestenchant = items[i].Enchant;
                List<Enchant> enchants = Enchant.Enchants[i];
                if (items[i].GetType() == typeof(Weapon))
                {
                    if ((items[i] as Weapon).TwoHand)
                    {
                        enchants = Enchant.TwoHand;
                    }
                }
                else if (items[i].GetType() == typeof(Armor))
                {
                    if ((items[i] as Armor).Type == ArmorProficiency.Shield)
                    {
                        enchants = Enchant.Shield;
                    }
                }
                for (int m = 0; m < enchants.Count; m++)
                {
                    items[i].Enchant = enchants[m];
                    bool valid = m_Target.evaluateEquip(items);
                    float fitness = -1;
                    if (valid) fitness = m_Target.evaluateTF();
                    if (fitness > maxfitness)
                    {
                        maxfitness = fitness;
                        bestenchant = items[i].Enchant;
                    }
                    else
                    {
                        items[i].Enchant = bestenchant;
                    }
                }
                if (Optimizer.m_Abort) break;
            }
            m_MaxTV = maxfitness;
            return items;
        }
        public OptimizeAdditional()
        {
            EnableNotification = false;
        }
        public override void Optimize()
        {
            Monitor.Enter(m_Target);
            try
            {
                // optimize two times ;)
                m_Target.Slots = optimizeGems(m_Target.Slots, m_MaxTV, m_Items[m_Items.Length - 1]);
                m_Target.Slots = optimizeGems(m_Target.Slots, m_MaxTV, m_Items[m_Items.Length - 1]);
                m_Target.Slots = optimizeEnchants(m_Target.Slots, m_MaxTV);
            }
            finally
            {

                Monitor.Exit(m_Target);
                if (UpdateGraphics != null) UpdateGraphics(m_MaxTV);
                if (EnableNotification) Notify();
            }
        }
    }
}
